package com.youzi.tunnel.server.handlers;

import com.alibaba.fastjson.JSONObject;
import com.youzi.tunnel.common.protocol.Constants;
import com.youzi.tunnel.common.protocol.Message;
import com.youzi.tunnel.server.entity.Client;
import com.youzi.tunnel.server.entity.Tunnel;
import com.youzi.tunnel.server.manager.ClientManager;
import com.youzi.tunnel.server.manager.FutureManager;
import com.youzi.tunnel.server.manager.TunnelManager;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Collection;


@Slf4j
public class IdleHeartbeatHandler extends IdleStateHandler {

    public static final int READ_IDLE_TIME = 180;
    public static final int WRITE_IDLE_TIME = 175;

    public IdleHeartbeatHandler() {
        super(READ_IDLE_TIME, WRITE_IDLE_TIME, 0);
    }

    @Override
    protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
        Channel channel = ctx.channel();
        String clientId = channel.attr(Constants.CLIENT_ID).get();

        InetSocketAddress address = (InetSocketAddress) (ctx.channel().remoteAddress());
        if (clientId != null) {
            //如果不空则为客户端链路
            if (evt.state() == IdleState.WRITER_IDLE) {
                Client client = ClientManager.getClient(clientId);
                client.setChannel(null);
                client.setOnline(false);

                Collection<Tunnel> tunnels = TunnelManager.getRelevantTunnelByClient(clientId);
                tunnels.forEach(tunnel -> {
                    tunnel.setAlive(false);
                    //下发对向客户端关闭监听端口
                    if (tunnel.getFromClient().equals(clientId)) {
                        String toClient = tunnel.getToClient();
                        if (toClient.equals("server")) {
                            //如果对向客服端是服务器,直接停止监听端口
                            try {
                                FutureManager.close(tunnel.getId());
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Channel toChannel = ClientManager.getClient(toClient).getChannel();

                            Message message = new Message();
                            message.setType(Message.TYPE.CLOSE_PORT);
                            message.setData(JSONObject.toJSONString(tunnel).getBytes(StandardCharsets.UTF_8));

                            toChannel.writeAndFlush(message);
                        }
                    }

                });
                channel.close().sync();
                log.info("客户端关闭[{}:{},clientId={},channelId={}], message: 客户端超时", address.getHostString(), address.getPort(), clientId, channel.id());
            }
        } else {
            //否则为隧道链路
            Channel towardChannel = channel.attr(Constants.TOWARD_CHANNEL).get();

            Message message = new Message();
            message.setType(Message.TYPE.CLOSE_CONNECT);

            //下发关闭对向连接链路
            towardChannel.writeAndFlush(message);
            towardChannel.close().sync();
            channel.close().sync();
            log.info("隧道链路关闭[{}:{},{}<->{}], message: 链路闲置", address.getHostString(), address.getPort(), channel.id(), towardChannel.id());
//            log.info("出现链路闲置");
        }
    }
}
